'''
Created on 2010/07/06

@author: yukiyonezawa
'''

import re
import binascii

class Util(object):

    d2h = {'0': '0',
           '1': '1',
           '2': '2',
           '3': '3',
           '4': '4',
           '5': '5',
           '6': '6',
           '7': '7',
           '8': '8',
           '9': '9',
           '10': 'A',
           '11': 'B',
           '12': 'C',
           '13': 'D',
           '14': 'E',
           '15': 'F'}

    b2h = { '0000': '0',
            '0001': '1',
            '0010': '2',
            '0011': '3',
            '0100': '4',
            '0101': '5',
            '0110': '6',
            '0111': '7',
            '1000': '8',
            '1001': '9',
            '1010': 'A',
            '1011': 'B',
            '1100': 'C',
            '1101': 'D',
            '1110': 'E',
            '1111': 'F'}

    h2b = { '0': '0000',
            '1': '0001',
            '2': '0010',
            '3': '0011',
            '4': '0100',
            '5': '0101',
            '6': '0110',
            '7': '0111',
            '8': '1000',
            '9': '1001',
            'A': '1010',
            'B': '1011',
            'C': '1100',
            'D': '1101',
            'E': '1110',
            'F': '1111'}

    commonRootOIDs = {'28F84A': 3,      #1 0 159634
                      '28B27B': 4,      #1 0 6523
                      '28F863': 5,      #1 0 15459
                      '28FC59': 8,      #1 0 15961
                      '28FC5909': 9,    
                      '28FC590A': 10,
                      '28FC590B': 11,
                      '28FC590C': 12}

    dataFormats = {'3': '28F84A',
                   '4': '28B27B',
                   '5': '28F863',
                   '8': '28FC59',
                   '9': '28FC5909',
                   '10': '28FC590A',
                   '11': '28FC590B',
                   '12': '28FC590C'}

    appCMDs = {'28FC597E01': '1',
               '28FC597E02': '2',
               '28FC597E03': '3',
               '28FC597E04': '4',
               '28FC597E05': '5',
               '28FC597E06': '6',
               '28FC597E07': '7',
               '28FC597E08': '8',
               '28FC597E09': '9',
               '28FC597E0A': '10',
               '28FC597E0B': '11',
               '28FC597E0C': '12',
               '28FC597E0D': '13',
               '28FC597E0E': '14',
               '28FC597E0F': '15',
               '28FC597E10': '16'}

    """docstring for Tools"""
    def __init__(self):
        pass
    
    @staticmethod
    def convertHexToBinaryHex(hexValue):
        """for use air command"""
        hexValueBinary = re.sub('0x', '', hexValue)
        return binascii.unhexlify(hexValueBinary)
    
    
    @staticmethod
    def calculateXOR(command):
       result = 0
       for index, command_hex in enumerate(command):
           if index == 0:
               result = int(binascii.b2a_hex(command_hex), 16)
               continue
           result = result ^ int(binascii.b2a_hex(command_hex), 16)
          
       return re.sub('0x', '', hex(result))
       #return binary
       # return re.sub('0x', '', hex(result-1))
    
    @staticmethod
    def convertIntToBinaryHex(intValue, minLength = 2):
        hexValueBinary = re.sub('0x', '', hex(intValue))
        if len(hexValueBinary) > minLength:
            raise "ERROR length is not mutch"
        if len(hexValueBinary) < minLength:
            hexValueBinary = hexValueBinary.zfill(minLength)
        return binascii.unhexlify(hexValueBinary)
    
    
    @classmethod
    def convertBitToHex(cls, strBit):
        """ Converts bit string to its Hex value. ('11011010' to 'DA') 
        """
        temp = strBit
        strHex = ''  
        
        for i in range(len(strBit) / 8):
            strHex += cls.b2h.get(temp[:4])
            strHex += cls.b2h.get(temp[4:8])
            temp = temp[8:]
        return strHex
    
    @classmethod
    def convertHexToBit(cls, strHex):
        """ Converts hex string to its bit value. ('DA' to '11011010')
        """
        strBit = ''
        upperStrHex = strHex.upper()
        for h in upperStrHex:
            strBit += cls.h2b.get(h)
        return strBit
    
    @staticmethod
    def convertIntToHexNotMax(intValue):
        """ Converts integer to its Hex value. (14 -> '0E')
        """
        hexValue = re.sub('0x', '', hex(intValue))

        if hexValue[len(hexValue) - 1] == 'L':
            hexValue = hexValue[:len(hexValue) - 1]
        return hexValue
            
    @staticmethod
    def convertIntToHex(intValue, minLength = 2):
        """ Converts integer to its Hex value. (14 -> '0E')
        """
        hexValue = re.sub('0x', '', hex(intValue))
        if len(hexValue) > minLength:
            raise "Error length is not mutc"
        
        if len(hexValue) < minLength:
            hexValue = hexValue.zfill(minLength)
        
        if hexValue[len(hexValue) - 1] == 'L':
            hexValue = hexValue[:len(hexValue) - 1]
        return hexValue.upper()
    
    @staticmethod
    def convertBinaryToDecimal(bin=''):
        """ Converts binary value to decimal value. ('10001' -> 17)
        """
        integer = 0
        bin = bin.lstrip('0')
        if bin == '':
            integer = 0
        else:
            length = len(bin)
            for b in range(length):
                integer += 2 ** (length - 1 - b) * int(bin[b])
        return integer
    
    @staticmethod
    def convertIntToBit(integer=None, length=0):
        """ Converts decimal value to binary value. (17 -> '10001')
        """
        if integer == 0 :
            binaryString = '0'
            return binaryString.zfill(length)
            
        binary = list()
        while integer != 1:
            binary.append(str(integer % 2))
            integer = integer / 2
        
        binary.append('1')
        binary.reverse()
        if length == 0:
            return ''.join(binary)
        
        binaryString = ''.join(binary)
        return binaryString.zfill(length)
    
    @classmethod
    def convertDIToOID(di):
        """ Converts DI code to arc value in ISO/IEC 15961. (1P -> 48)
        """
        if len(di) == 1:
            return ord(di) - 64
        else:
            latterTemp = Util.convertIntToBit(ord(di[-1]) - 64)
            latter = '0' * (5 - len(latterTemp)) + latterTemp
            former = Util.convertIntToBit(int(di[:-1]))
            return Util.convertBinaryToDecimal(former + latter)
    
    def convertOIDToDI(self, oid):
        """ Converts arc value in ISO/IEC 15961 to DI code. (48 -> 1P)
        """
        if oid <= 26:
            return chr(oid + 64)
        else:
            diBinary = Util.convertIntToBit(oid)
            latter = chr(Util.convertBinaryToDecimal(diBinary[-5:]) + 64)
            former = Util.convertBinaryToDecimal(diBinary[:-5])   
            return str(former) + latter

    @staticmethod
    def convertExtensibleBitVectorToBit(value, length):

        length_extention_counter = 1
        while True:
            if value < int("1" + "0" * (length - 1) * length_extention_counter, 2):
                break
            length_extention_counter += 1
        
        value -= (int("1" + "0" * (length - 1) * (length_extention_counter - 1), 2) - 1)
        
        current_value = value
        non_extention_flag =  Util.convertIntToBit(current_value, (length - 1) * length_extention_counter)
        return_bit_value = ""
        max_length = (length - 1) * (length_extention_counter)
        
        for index in range(length_extention_counter):            
            extention_bit = ""
            #add extention bit
            if index != length_extention_counter - 1:
                extention_bit += "1"
            else:
                extention_bit += "0"
            
            current_bit = extention_bit + non_extention_flag[ max_length - (index * (length - 1)) - (length-1):max_length - (index* (length-1))]
            return_bit_value = return_bit_value + current_bit
        
        return return_bit_value
    
    @staticmethod
    def convertExtensibleBitVertorToInt(value, length):        
        """
        hidden value + shown value
        """
        temp_value = value[:length]
        value = value[length:]
        
        while True:
            if temp_value[0] == "0":
                break            
            temp_value = value[:length] + temp_value            
            value = value[length:]
        
        length_extention_counter = len(temp_value) / length
        hiddened_value = int("1" + "0" * (length - 1) * (length_extention_counter - 1) , 2) - 1        
        
        bit_value = ""
        for index in range(length_extention_counter):
            start = index * length + 1
            end = start + length - 1
            bit_value =  bit_value + temp_value[start:end]
        
        return int(bit_value, 2) + hiddened_value
    
    @staticmethod
    def parseExtensibleBit(tag_id, driver, start_address, start_bit, extensible_length):

        temp_start_address = start_address
        
        extensible_hex = driver.readUserMemory(tag_id, start_address, 1)
        start_address += 1        
        extensible_bit = Util.convertHexToBit(extensible_hex)[start_bit:]
        while True:
            if len(extensible_bit) >= extensible_length:
                break
            extensible_hex = driver.readUserMemory(tag_id, start_address, 1)
            extensible_bit = extensible_bit + Util.convertHexToBit(extensible_hex)
            start_address += 1
        
        connected_bit = ""
        while True:
            if extensible_bit[0] == "1":
                #is extensioned
                connected_bit =  connected_bit + extensible_bit[0:extensible_length]
                extensible_bit = extensible_bit[extensible_length]                
                while True:
                    if len(extensible_bit) >= extensible_length:
                        break                    
                    extensible_hex = driver.readUserMemory(tag_id, start_address, 1)
                    start_address += 1
                    extensible_bit = extensible_bit + Util.convertHexToBit(extensible_hex)                
            else:
                connected_bit =  connected_bit + extensible_bit[0:extensible_length]
                break
        
        temp_start_address += len(connected_bit) / 8
        start_bit = len(connected_bit) % 8        
        return {"EXTENSIBLE_BIT":connected_bit, "NEXT_START_ADDRESS":temp_start_address, "NEXT_START_BIT":start_bit}
    
        
if __name__ == '__main__':
#    print Util.convertExtensibleBitVectorToBit(10, 4)
    print Util.convertExtensibleBitVertorToInt("10110000", 4)
#    Util.convertExtensibleBitVertorToInt("1000000100000000", 8)
